/**
* @file register.cpp
*
*	 Nel file register.cpp vengono implementate tutte le funzionalità messe a
*	 descritte nel file register.h
*	 In questo Registro ogni Service Provider può registrare diversi servizi e, più
*	 in generale, diversi Service Provider possono registrare uno stesso tipo di 
*	 servizio.
*
* @author Favale Angelo
* @author Fagioli Alessio
*
* @version 1.0
*/

#include "register.h"

int decode_msg_from_SP(char * buffer, char * porta, char * ip)
{
	// in buffer c'è un messaggio del tipo: "0;nome_servizio;porta_service;ip_service"
	// oppure 				"1;nome_servizio;porta_service;ip_service"	
	
	char num_service[BUFFER_SIZE];	
	
	memset(num_service,0,BUFFER_SIZE);
	memset(porta,0,BUFFER_SIZE);
	memset(ip,0,INET_ADDRSTRLEN);

	

	int i=2;

	while (buffer[i] != ';' && i<BUFFER_SIZE)
	{	
		num_service[i-2]=buffer[i];
		i++;
		
	}
	
	if (i==BUFFER_SIZE)
		return -1;


	i++; //salto ';'
	

	while (buffer[i] != ';' && i<BUFFER_SIZE)
	{	
		porta[i-3-strlen(num_service)]=buffer[i];
		i++;
		
	}

	if (i==BUFFER_SIZE)
		return -1;

	i++;
	
	while (buffer[i] != '#' && i<BUFFER_SIZE)
	{	
		ip[i-4-strlen(num_service)-strlen(porta)]=buffer[i];
		i++;
		
	}
	if (i==BUFFER_SIZE)
		return -1;


	return (atoi(num_service));
}


bool receive_name_service (char *name_service,int s)
{
	memset(name_service,0,BUFFER_SIZE);	
	int i=0;

	do
		recv (s,&name_service[i],1,0);
	
	while (name_service[i++]!=';' && i<BUFFER_SIZE);

	name_service[i-1]='\0';

	if (i==BUFFER_SIZE)
		return false;
	else
		return true;


}

bool decode_msg_from_client(char * buffer, char * nome_servizio)
{
	int i=2;
	
	memset(nome_servizio,0,BUFFER_SIZE);

	while (buffer[i] != '#' && i< BUFFER_SIZE)
	{			
		nome_servizio[i-2]=buffer[i];
		i++;
	}
		
	if(i==BUFFER_SIZE)
		return false;
	
	return true;


}

Register::Register()
{
	first = NULL;
}

bool Register::add_node(char name[], host service_provider)
{
	node *p = new node;
	strcpy(p->name_service,name);
	strcpy(p->ip,service_provider.ip);
	p->porta=service_provider.porta;
	
	if (first == NULL)
	{	
		first=p;
		p->next_service = NULL;
		p->same_service = NULL;
		return true;
	}

	node * find;
	node * precedent;
	
	find = first;
	precedent = NULL;
	
	while (find != NULL)
	{
	
		if (!strcmp(find->name_service,name))
		{
		//servizio già presente nella lista principale

			if (!precedent) 
			{
				//caso in cui il servizio è già presente, ed è il primo della lista principale
				p->same_service=first;			
				p->next_service=first->next_service;
				first=p;			
			}
			else 
			{
				p->next_service = find->next_service;
				p->same_service = find;
				precedent->next_service = p;
			}			
			return true;
		}
		precedent = find;
		find = find->next_service;

	}

	//servizio non è già presente nella lista principale e va inserito
	
	
	precedent->next_service = p;
	p->next_service = NULL;
	p->same_service = NULL;
	
	return true;
}


host* Register::extract_node(char name[])
{
	node *p = first;
	node *precedent = NULL;
	node *find;
	node *find_precedent;
	host *ret;

	while (p != NULL)
	{
		
		if (!strcmp(p->name_service,name))
		{
		//Trovata la sottolista di quel servizio

			if (p->same_service == NULL)
			{
				//La sottolista è composta da un solo elemento				
				ret=new host;
				strcpy(ret->ip,p->ip);
				ret->porta=p->porta;
				return ret;
			}
		
			find = p;
			find_precedent = NULL;

			//Scorro fino all'ultimo elemento sottolista
			while (find->same_service != NULL)
			{
				find_precedent = find;
				find = find->same_service;
			}
		
		
			//Ultimo elemento diventa il primo della sottolista
			find_precedent->same_service = NULL;
			find->next_service = p->next_service;
			find->same_service = p;
		
			if(precedent != NULL)
				precedent->next_service = find;
			else
				//se servizio è il primo elemento della lista principale			
				first = find;
			
			ret=new host;
			
			strcpy(ret->ip,find->ip);
			ret->porta=find->porta;
			return ret;
			//ritorna elemento corretto			
		}
		precedent=p;		
		p = p->next_service;
		//scorro lista principale
	}

	//il servizio cercato non è disponibile
	return NULL;
}


bool Register::rm_service_provider (char ip[], int porta, char service[]){

	node *p = first;
	node *precedent = NULL;
	node *find;
	node *find_precedent;

	while (p != NULL)
	{
	
		if (!strcmp(p->name_service,service))
		{
		
			//trovato servizio, entro in sottolista	
			
			find = p;
			find_precedent = NULL;

			while(find!=NULL && !((!strcmp (find->ip,ip)) && (porta==find->porta)))
			{
			//scorro finchè non trovo serviceprovider o fine sottolista			
				find_precedent = find;
				find = find->same_service;
			}

			if (find==NULL)
				{printf("ATTENZIONE: Ip e Porta non presente in lista per quel servizio\n");				
					//serviceprovider non presente in sottolista
				return false;}
		
				
			if (find_precedent == NULL)
					{
					//Primo elemento sottolista
				
					if(precedent ==NULL)
					
						//primo elemento della lista principale
				
						if(find->same_service==NULL)
						//unico elemento sottolista
							first=find->next_service;
						else
							{first=find->same_service;
							find->same_service->next_service=find->next_service;}
					else		
						{					
						if(find->same_service!=NULL)
							{precedent->next_service=find->same_service;
							find->same_service->next_service=find->next_service;}
						else
							precedent->next_service=find->next_service;
						
							//sottolista composta da almeno 2 elementi						
							
						}

					free (find);				
					return true;
					}
		
			// elemento qualsiasi sottolista
			find_precedent->same_service=find->same_service;
			free (find);
			return true;
				
		}
		//scorro lista principale in cerca del servizio
		precedent=p;		
		p = p->next_service;
		
	}
	printf("ATTENZIONE: Il servizio non è presente nella lista\n");
	//il servizio cercato non è disponibile
	return false;
			
	}

